#include "stdafx.h"
#include <atlbase.h>
#include <cemapi.h>
#include <mapiutil.h>
#include "resource.h"

/////////////////////////////////////////////////////////////////////////////////////////////
// This function is used to get the msgstore named SMS from msgstores on the
// device.
// I could have used just raw pointers but it is much easier and safer to just
// use smart pointers.
HRESULT GetSMSMsgStore(const CComPtr<IMAPISession>& spSession,
					   CComPtr<IMsgStore>& spMsgStore)
{
	// first we get the msgstores table from the session
	CComPtr<IMAPITable> spTable;
	HRESULT hr = spSession->GetMsgStoresTable(MAPI_UNICODE, &spTable);
	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FAIL_MSGSTORE_TABLES);
		return FALSE;
	}

	// next we loop over the message stores opening each msgstore and
	// getting its name to see if the name matches SMS.
	// If it does then we break out of the loop
	while (TRUE)
	{
		SRowSet* pRowSet = NULL;
		hr = spTable->QueryRows(1, 0, &pRowSet);

		// If we failed to query the
		// rows then we need to break
		if (FAILED(hr))
		{
			//AfxMessageBox(IDS_SMS_FAILEDTABLE);
			break;
		}

		// if we got no rows back then just exit the loop
		//remembering to set an error
		if (pRowSet->cRows == 1)
		{
			spMsgStore.Release();
			spMsgStore = NULL;
			ASSERT(pRowSet->aRow[0].lpProps->ulPropTag == PR_ENTRYID);
			SBinary& blob = pRowSet->aRow[0].lpProps->Value.bin;
			hr = spSession->OpenMsgStore(NULL,
										 blob.cb, (LPENTRYID)blob.lpb,
										 NULL, 0, &spMsgStore);
			if (FAILED(hr))
			{
				//AfxMessageBox(IDS_SMS_FAILED_OPENMSGSTORE);
			}

		}
		else
		{
			//AfxMessageBox(IDS_SMS_MSGSTORENOTFOUND);
			hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
		}

		// now remember to free the row set
		FreeProws(pRowSet);
		if (FAILED(hr))
		{
			break;
		}

		// now get the display name property from the
		// message store to compare it against the name
		// 'SMS'
		SPropTagArray props;
		props.cValues = 1;
		props.aulPropTag[0] = PR_DISPLAY_NAME;

		ULONG cValues;
		SPropValue* pProps = NULL;
		hr = spMsgStore->GetProps(&props, MAPI_UNICODE, &cValues, &pProps);
		if (FAILED(hr) || cValues != 1)
		{
			//AfxMessageBox(IDS_SMS_FAILED_GETNAME);
			break;
		}

		// if the name matches SMS then break and as
		// hr == S_OK the current MsgStore smart pointer
		// will correctly be set.
		if (_tcsicmp(pProps[0].Value.lpszW, _T("SMS")) == 0)
		{
			break;
		}
	}

	// if we failed for some reason then we clear out
	// the msgstore smartpointer and return the error.
	if (FAILED(hr))
	{
		spMsgStore.Release();
	}

	return hr;
}


/////////////////////////////////////////////////////////////////////////////////////////////
// This function is used to get the folder named drafts from the msgstore on the
// device.
// I could have used just raw pointers but it is much easier and safer to just
// use smart pointers.
HRESULT GetSMSFolder(const CComPtr<IMsgStore>& spMsgStore, CComPtr<IMAPIFolder>& spFolder)
{
	// Now get the Drafts folder.
	SPropTagArray propDefaultFolder;
	propDefaultFolder.cValues = 1;
	propDefaultFolder.aulPropTag[0] = PR_CE_IPM_DRAFTS_ENTRYID;

	ULONG			cValues;
	LPSPropValue	pPropVals;
	HRESULT hr = spMsgStore->GetProps(&propDefaultFolder,
									  MAPI_UNICODE, &cValues, &pPropVals);
	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FOLDERNOTFOUND);
		return hr;
	}

	SBinary& eidDrafts = pPropVals->Value.bin;

	hr = spMsgStore->OpenEntry(eidDrafts.cb, (LPENTRYID)eidDrafts.lpb,
							   NULL, MAPI_MODIFY, NULL,
							   (LPUNKNOWN*) & spFolder);
	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FOLDERNOTOPENED);
	}

	return hr;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// This function is used to get the send the message.
// This uses an opened MAPI session
HRESULT SendSMSMessage(const CComPtr<IMAPIFolder>& spFolder,
					   LPCTSTR lpszFrom,
					   LPCTSTR lpszTo, LPCTSTR lpszMessage)
{
	CComPtr<IMessage> spMessage;
	HRESULT hr = spFolder->CreateMessage(NULL, 0 , &spMessage);
	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FAIL_CREATEMESSAGE);
		return hr;
	}

	// set the recipients
	// set up the required fields for a recipient
	SPropValue propRecipient[3];
	// it is vital we clear the property structure
	// as there are fields we do not use but MAPI seems
	// to be sentative to them.
	ZeroMemory(&propRecipient, sizeof(propRecipient));
	// set the recipient type which could be to, cc, bcc
	// but ehre must at least be a to field
	propRecipient[0].ulPropTag = PR_RECIPIENT_TYPE;
	propRecipient[0].Value.l = MAPI_TO;

	// we set the type of address to sms instead of
	// smtp
	propRecipient[1].ulPropTag = PR_ADDRTYPE;
	propRecipient[1].Value.lpszW = _T("SMS");
	// we finally set the email address to the
	// phone number of the person we are sending the message
	// to
	propRecipient[2].ulPropTag = PR_EMAIL_ADDRESS;
	propRecipient[2].Value.lpszW = (LPWSTR)lpszTo;

	// set the address-list to point to the properties
	ADRLIST adrlist;
	adrlist.cEntries = 1;
	adrlist.aEntries[0].cValues = 3;
	adrlist.aEntries[0].rgPropVals = (LPSPropValue)(&propRecipient);

	// finally modify the recipients of the message
	hr = spMessage->ModifyRecipients(MODRECIP_ADD, &adrlist);

	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FAILED_ADDRECIPIENTS);
		return hr;
	}
	else
		; // added the recipient to the message

	// now we set the additional properties for the
	// message
	SPropValue props[4];

	//note how we zero out the contents of the
	// structure as MAPI is sensitive to the
	// contents of other fields we do not use.
	ZeroMemory(&props, sizeof(props));

	// first set the subject of the message
	// as the sms we are going to send
	props[0].ulPropTag = PR_SUBJECT;
	props[0].Value.lpszW = (LPWSTR)lpszMessage;

	// next set the senders email address to
	// the phone number of the person we are
	// sending the message to
	props[1].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
	props[1].Value.lpszW = (LPWSTR)lpszFrom;

	// finally and most importantly tell mapi
	// this is a sms message in need of delivery
	props[2].ulPropTag = PR_MSG_STATUS;
	props[2].Value.ul = MSGSTATUS_RECTYPE_SMS;

	props[3].ulPropTag = PR_MESSAGE_FLAGS;
	props[3].Value.ul = MSGFLAG_FROMME | MSGFLAG_UNSENT;

	hr = spMessage->SetProps(sizeof(props) / sizeof(props[0]), (LPSPropValue) & props, NULL);
	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FAIL_SETPROPS);
		return hr;
	}

	// having set all the required fields we can now
	// pass the message over to the msgstore transport
	// to be delivered.
	hr = spMessage->SubmitMessage(0);
	if (FAILED(hr))
	{
		//AfxMessageBox(IDS_SMS_FAIL_SUBMITMSG);
		return hr;
	}

	return FALSE;
}
